home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et-2_2.lha / et2.2 / src / Document.C < prev    next >
C/C++ Source or Header  |  1990-12-19  |  12KB  |  588 lines

  1. #include "ET++.h"
  2.  
  3. #include "FileDialog.h"
  4. #include "System.h"
  5. #include "Icon.h"
  6. #include "ObjList.h"
  7. #include "ObjectTable.h"
  8. #include "ClassManager.h"
  9.  
  10. static FileDialog *loadDialog, *saveDialog, *importDialog;
  11.  
  12. static u_short FileBits[]= {
  13. #   include "images/file.im"
  14. };
  15.  
  16. //---- Document ----------------------------------------------------------------
  17.  
  18. AbstractMetaImpl(Document, (TP(application), T(changeCount), T(uniqueId),
  19.     TP(docName), TP(docType), TP(lastCmd), TP(menu), TB(isUntitled), 
  20.     TB(isOpen), TB(isConverted), TP(loadDir), TP(window), TP(icon),
  21.     TP(windows), TB(makeBackup), 0));
  22.  
  23.  
  24. Document::Document(const char *dt)
  25. {
  26.     changeCount= 0;
  27.     lastCmd= gNoChanges;
  28.     menu= new Menu("edit");
  29.     icon= 0;
  30.     window= 0;
  31.     windows= new ObjList;
  32.     isOpen= TRUE;
  33.     application= 0;
  34.     docName= 0;
  35.     loadDir= 0;
  36.     docType= dt;
  37.     isUntitled= TRUE;
  38.     isConverted= FALSE;
  39.     makeBackup= FALSE;
  40.     uniqueId= 0;
  41. }
  42.  
  43. Document::~Document()
  44. {
  45.     if (lastCmd && lastCmd != gResetUndo)
  46.     Error("~Document", "lastCmd != gResetUndo");
  47.     SafeDelete(lastCmd);
  48.     SafeDelete(menu);
  49.     SafeDelete(docName);
  50.     SafeDelete(loadDir);
  51.     SafeDelete(icon);
  52.     SafeDelete(windows);
  53.     SafeDelete(window);
  54. }
  55.  
  56. FileDialog *Document::MakeFileDialog(FileDialogType)
  57. {
  58.     return application->MakeFileDialog();
  59. }
  60.  
  61. void Document::SetName(char *name)
  62. {
  63.     if ((docName == 0) || (strcmp(name, docName) != 0)) {
  64.     strreplace(&docName, name);
  65.     if (window)
  66.         SetWindowTitle(docName);
  67.     }
  68. }
  69.  
  70. void Document::SetWindowTitle(char *docName)
  71. {
  72.     window->SetTitle(docName);
  73. }
  74.  
  75. EvtHandler *Document::GetNextHandler()
  76. {
  77.     return application;
  78. }
  79.  
  80. void Document::SetApplication(Application *app)
  81. {
  82.     application= app;
  83. }
  84.  
  85. void Document::OpenWindows()
  86. {
  87.     Point lastDocPos= application->GetNewDocumentPos();
  88.     if (window= DoMakeWindows())
  89.     windows->AddFirst(window);
  90.     if (window= Guard(windows->First(), Window)) {
  91.     DoMakeViews();
  92.     char *name= window->GetTitle();
  93.     if (name == 0 || *name == '\0')
  94.         window->SetTitle(docName, FALSE);
  95.     window->OpenAt(lastDocPos);
  96.     }
  97. }
  98.  
  99. Window *Document::DoMakeWindows()
  100. {
  101.     return 0;
  102. }
  103.  
  104. void Document::AddWindow(BlankWin *win)
  105. {
  106.     windows->Add(win);
  107. }
  108.  
  109. void Document::DoMakeViews()
  110. {
  111.     // Warning("DoMakeViews", "method is obsolete, use DoMakeWindows!!"
  112. }
  113.  
  114. void Document::Toggle()
  115. {
  116.     if (window) {
  117.     BlankWin *win;
  118.     Iter next(windows);
  119.     bool isopen= TRUE;
  120.     
  121.     if (icon == 0) {
  122.         icon= DoMakeIcon(GetName());
  123.         icon->OpenAt(window->GetRect().origin);
  124.     } else
  125.         icon->Open(isopen= !icon->IsOpen());
  126.  
  127.     for (int i= 0; win= (BlankWin*) next(); i++) {
  128.         if (isopen) {
  129.         win->SetFlag(eBWinWasOpen, win->IsOpen());
  130.         win->Close();
  131.         } else {
  132.         if (win->TestFlag(eBWinWasOpen))
  133.             win->Open();
  134.         }
  135.     }
  136.     if (isopen)
  137.         icon->UpdateIconLabel(GetName());
  138.     }
  139. }
  140.  
  141. Icon *Document::DoMakeIcon(char *name)
  142. {
  143.     if (gFileIcon == 0)
  144.     gFileIcon= new Bitmap(16, FileBits);
  145.     return
  146.     new Icon(this,
  147.         new BorderItem(
  148.         new Cluster(cIdNone, eVObjHCenter, gPoint2,
  149.             new ImageItem(gFileIcon, 13),
  150.             new TextItem(cIdIconLabel, name, new_Font(eFontTimes, 9)),
  151.             0
  152.         ), gPoint2, 2, eVObjHCenter));
  153. }
  154.  
  155. //---- Menus --------------------------------------------------------------------
  156.  
  157. Menu *Document::GetMenu()
  158. {
  159.     return menu;
  160. }
  161.  
  162. void Document::DoCreateMenu(Menu *menu)
  163. {
  164.     Menu *file= new Menu("file");
  165.  
  166.     EvtHandler::DoCreateMenu(menu);
  167.  
  168.     file->AppendItems(
  169.              "load ...",                 cLOAD,
  170.              "-",
  171.              "save",                     cSAVE,
  172.              "save as ...",              cSAVEAS,
  173.              "revert",                   cREVERT,
  174.              "close",                    cCLOSE,
  175.              "-",
  176.              "application window",       cSHOWAPPLWIN,
  177.              0);
  178.     
  179.     if (CanImportDocument(0))
  180.     file->InsertItemAfter(cLOAD, "import ...", cIMPORT);
  181.     
  182.     menu->AppendItems("undo",   cUNDO,
  183.               "-",
  184.               "cut",    cCUT,
  185.               "copy",   cCOPY,
  186.               "paste",  cPASTE,
  187.               "-",
  188.              0);
  189.  
  190.     menu->AppendMenu(file, cFILEMENU);
  191. }
  192.  
  193. void Document::DoSetupMenu(Menu *menu)
  194. {
  195.     EvtHandler::DoSetupMenu(menu);
  196.     if (lastCmd != gNoChanges) {
  197.     menu->ReplaceItem(cUNDO, lastCmd->GetUndoName());
  198.     if (lastCmd->TestFlag(eCmdCanUndo))
  199.         menu->EnableItem(cUNDO);
  200.     }
  201.     if (Modified()) {
  202.     menu->EnableItem(cSAVE);
  203.     if (!isUntitled)
  204.         menu->EnableItem(cREVERT);
  205.     }
  206.     menu->EnableItems(cCLOSE, cLOAD, cSAVEAS, cSHOWAPPLWIN, cFILEMENU, cIMPORT, 0);
  207. }
  208.  
  209. Command *Document::DoMenuCommand(int cmd)
  210. {
  211.     switch(cmd) {
  212.     case cUNDO:
  213.     Undo();
  214.     break;
  215.  
  216.     case cREDO:
  217.     Redo();
  218.     break;
  219.  
  220.     case cSAVE:
  221.     Save();
  222.     break;
  223.  
  224.     case cSAVEAS:
  225.     SaveAs();
  226.     break;
  227.  
  228.     case cLOAD:
  229.     Open();
  230.     break;
  231.  
  232.     case cIMPORT:
  233.     return Import();
  234.     
  235.     case cCLOSE:
  236.     Close();
  237.     break;
  238.  
  239.     case cREVERT:
  240.     Revert();
  241.     break;
  242.  
  243.     case cCOLLAPSE:
  244.     Toggle();
  245.     break;
  246.     
  247.     default:
  248.     return EvtHandler::DoMenuCommand(cmd);
  249.     }
  250.     if (window)
  251.     window->UpdateEvent();
  252.     return gNoChanges;
  253. }
  254.  
  255. void Document::Control(int id, int part, void *vp)
  256. {
  257.     if (id == cIdWinDestroyed) 
  258.     windows->RemovePtr((Object*)vp);
  259.     else if (id == cIdCloseBox) 
  260.     Toggle();
  261.     EvtHandler::Control(id, part, vp);
  262. }
  263.  
  264. void Document::PerformCommand(Command* cmd)
  265. {
  266.     // don't do anything on gNoChanges!!
  267.     if (cmd && (cmd != gNoChanges) && (cmd->GetId() || cmd == gResetUndo)) {
  268.     if (lastCmd)
  269.         lastCmd->Finish(cmd);
  270.     if (cmd != gResetUndo)
  271.         SetChangeCount(changeCount+= cmd->Do());
  272.     if (lastCmd)
  273.         lastCmd= cmd;
  274.     else
  275.         cmd->Finish(0);
  276.     }
  277.     if (window)
  278.     window->UpdateEvent();
  279. }
  280.  
  281. void Document::Undo()
  282. {
  283.     if (lastCmd)
  284.     SetChangeCount(changeCount+= lastCmd->Undo());
  285. }
  286.  
  287. void Document::Redo()
  288. {
  289. }
  290.  
  291. bool Document::Modified()
  292. {
  293.     return changeCount > 0; 
  294. }
  295.  
  296. bool Document::AlertChanges()
  297. {
  298.     return Modified();
  299. }
  300.  
  301. void Document::SetChangeCount(int c)
  302. {
  303.     changeCount= c;
  304. }
  305.  
  306. void Document::InitChangeCount()
  307. {
  308.     changeCount= 0;
  309. }
  310.  
  311. //---- Menu Commands -----------------------------------------------------------
  312.  
  313. bool Document::Open()
  314. {
  315.     if (AlertChanges()) {
  316.     switch(ShowAlert(eAlertCaution, "Save changes to @B%s@P ?", 
  317.                                BaseName(docName))) {
  318.     case cIdYes:
  319.         if (! Save())
  320.         return FALSE;
  321.         break;
  322.     case cIdNo:
  323.         break;
  324.     case cIdCancel:
  325.         return FALSE;
  326.     }
  327.     }
  328.  
  329.     PerformCommand(gResetUndo);
  330.  
  331.     if (loadDialog == 0)
  332.     ObjectTable::AddRoot(loadDialog= MakeFileDialog(eFDTypeRead));
  333.  
  334.     if (loadDialog->ShowInWindow(eFDRead, window, this) == cIdOk) {
  335.     char *filename= loadDialog->FileName();
  336.     FileType *ft= loadDialog->GetDocType();
  337.     if (CanLoadDocument(ft))
  338.         Load(filename, TRUE, ft);
  339.     else
  340.         application->OpenDocument(filename);
  341.     return TRUE;
  342.     }
  343.     return FALSE;
  344. }
  345.  
  346. bool Document::Close()   // return TRUE if OK
  347. {
  348.     bool closedoc= TRUE;
  349.  
  350.     if (! isOpen)
  351.     return closedoc;
  352.  
  353.     if (AlertChanges()) {
  354.     switch (ShowAlert(eAlertCaution, "Save changes to @B%s@P ?", 
  355.                                 BaseName(docName))) {
  356.     case cIdNo:
  357.         closedoc= TRUE;
  358.         break;
  359.     case cIdYes:
  360.         closedoc= Save();
  361.         break;
  362.     case cIdCancel:
  363.         closedoc= FALSE;
  364.         break;
  365.     }
  366.     }
  367.  
  368.     if (closedoc) {
  369.     PerformCommand(gResetUndo);
  370.     windows->ForEach(BlankWin,Open)(FALSE);
  371.     if (application)
  372.         application->RemoveDocument(this);
  373.     isOpen= FALSE;
  374.     }
  375.     return closedoc;
  376. }
  377.  
  378. bool Document::Save()
  379. {
  380.     if (AlertChanges() && (isUntitled || isConverted))
  381.     return SaveAs();
  382.  
  383.     if (! Modified()) {
  384.     ShowAlert(eAlertNote, "No changes since last save");
  385.     return TRUE;
  386.     }
  387.     MakeBackup(loadDir, docName);
  388.     char *name= form("%s/%s", loadDir, docName);
  389.     PerformCommand(gResetUndo);     //  Added by SMM, Kewill, 28/2/90 ???
  390.     if (docName[0] == '/') 
  391.     Store(docName, 0);
  392.     else 
  393.     Store(name, 0);
  394.     
  395.     // update id
  396.     uniqueId= FType(name).UniqueId();
  397.     
  398.     return TRUE;
  399. }
  400.     
  401. void Document::MakeBackup(char *loadDir, char *docName)
  402. {
  403.     if (makeBackup) {
  404.     char *name, backup[1000];
  405.     strcpy(backup, form("%s/%s%%", loadDir, docName)); 
  406.     name= form("%s/%s", loadDir, docName);
  407.     gSystem->Rename(name, backup);
  408.     }
  409. }
  410.  
  411. void Document::EnableBackups(bool onOff)
  412. {
  413.     makeBackup= onOff;
  414. }
  415.  
  416. bool Document::SaveAs()
  417. {
  418.     if (saveDialog == 0)
  419.     ObjectTable::AddRoot(saveDialog= MakeFileDialog(eFDTypeWrite));
  420.  
  421.     if (saveDialog->ShowInWindow(eFDWrite, window, this) == cIdOk) {
  422.     PerformCommand(gResetUndo);
  423.  
  424.     char *filename= saveDialog->FileName();
  425.     SetName(filename);
  426.     Store(filename, saveDialog->GetSaveOption());
  427.     FType ft(filename);
  428.     uniqueId= ft.UniqueId();
  429.     isUntitled= isConverted= FALSE;
  430.     strreplace(&loadDir, gSystem->WorkingDirectory());
  431.     return TRUE;
  432.     }
  433.     return FALSE;
  434. }
  435.  
  436. void Document::Revert()
  437. {
  438.     if (Modified() &&
  439.     ShowAlert(eAlertCaution, "Discard all changes of @B%s@P ?", 
  440.                           BaseName(docName)) == cIdYes){
  441.         FType ft(docName);
  442.         Load(docName, FALSE, ft.FileType());
  443.     }            
  444. }
  445.  
  446. Command *Document::Import()
  447. {
  448.     Command *cmd= gNoChanges;
  449.     
  450.     if (importDialog == 0)
  451.     ObjectTable::AddRoot(importDialog= MakeFileDialog(eFDTypeImport));
  452.  
  453.     if (importDialog->ShowInWindow(eFDImport, window, this) == cIdOk) {
  454.     char *filename= importDialog->FileName();
  455.     FileType *ft= importDialog->GetDocType();
  456.     if (CanImportDocument(ft)) {
  457.         istream from(filename);
  458.         gClassManager->Reset();
  459.         cmd= DoImport(from, ft);
  460.         gClassManager->Reset();
  461.     }
  462.     }
  463.     return cmd;
  464. }
  465.  
  466. //---- Load/Store Documents -----------------------------------------------------
  467.  
  468. bool Document::CanLoadDocument(FileType *file)
  469. {
  470.     bool ok= strcmp(GetDocumentType(), file->Type()) == 0;
  471.     if (!ok)
  472.     if (strcmp(GetDocumentType(), cDocTypeAscii) == 0 && file->IsAscii())
  473.         ok= TRUE;
  474.     return ok;
  475. }
  476.  
  477. bool Document::CanImportDocument(FileType *)
  478. {
  479.     return FALSE;
  480. }
  481.  
  482. bool Document::Load(char *name, bool unique, FileType *filetype)
  483. {
  484.     bool rcode= TRUE, asuntitled= FALSE;
  485.     int uid;
  486.     char *newname;
  487.     Document *doc;
  488.         
  489.     if ((uid= filetype->UniqueId()) == 0) {
  490.     ShowAlert(eAlertNote, "something wrong with @B%s@P\n%s", name,
  491.                             gSystem->GetErrorStr());
  492.     return FALSE;
  493.     }
  494.  
  495.     if (unique && (doc= application->FindDocument(uid))) {
  496.     if (DoFileIsAlreadyOpen(doc, name))
  497.         newname= name;   // show document once more
  498.     else
  499.         return FALSE;   
  500.     } else
  501.     newname= name;
  502.  
  503.     istream from(newname);
  504.     SetName(newname);
  505.  
  506.     gClassManager->Reset();
  507.     DoRead(from, filetype);
  508.     if (gClassManager->Reset() == 0) {
  509.     InitChangeCount();
  510.     isUntitled= asuntitled;
  511.     if ((strcmp(docType, cDocTypeAscii) == 0) && filetype->IsAscii())
  512.         isConverted= FALSE;
  513.     else
  514.         isConverted= strcmp(filetype->Type(), docType) != 0;
  515.     if (lastCmd && lastCmd != gNoChanges)
  516.         delete lastCmd;
  517.     lastCmd= gNoChanges;
  518.     }
  519.     strreplace(&loadDir, gSystem->WorkingDirectory());
  520.     uniqueId= uid;
  521.     return TRUE;
  522. }
  523.  
  524. bool Document::DoFileIsAlreadyOpen(Document *shown, char *name)
  525. {
  526.     ShowAlert(eAlertNote, "Document @B%s@P is already open", name);
  527.     ShowDocument(shown);
  528.     return FALSE;
  529. }
  530.  
  531. void Document::ShowDocument(Document *shown)
  532. {
  533.     Window *w= 0;
  534.     if (shown != this) {
  535.     if (w= shown->GetWindow())
  536.         if (!w->IsOpen())
  537.         shown->Toggle();
  538.         else
  539.         w->Open();
  540.     }   
  541. }
  542.  
  543. void Document::Store(char *name, int option)
  544. {
  545.     ostream to(name);
  546.  
  547.     gClassManager->Reset();
  548.     gInPrintOn= TRUE;
  549.     DoWrite(to, option);
  550.     gInPrintOn= FALSE;
  551.     gClassManager->Reset();
  552.  
  553.     SetChangeCount(0);
  554. }
  555.  
  556. void Document::DoRead(istream& from, FileType *)
  557. {
  558.     char c;
  559.     //overread magic cookie
  560.     while (from.get(c))
  561.     if (c == '\n')
  562.         break;
  563. }
  564.  
  565. void Document::DoWrite(ostream& to, int)
  566. {
  567.     to << cMagic << docType SP << application->ProgramName() NL;
  568. }
  569.  
  570. Command *Document::DoImport(istream& , FileType *)
  571. {
  572.     return gNoChanges;
  573. }
  574.  
  575. void Document::InspectorId(char *buf, int bufSize)
  576. {
  577.     if (docName)
  578.     strn0cpy(buf, docName, bufSize);
  579.     else
  580.     EvtHandler::InspectorId(buf, bufSize);        
  581. }
  582.  
  583. void Document::Parts(Collection* col)
  584. {
  585.     EvtHandler::Parts(col);
  586.     col->AddVector(windows, menu, 0);
  587. }
  588.